/**************************************************************************
RC5 is a BWT/RLE-0/MTF-2/SM pipeline compressor

It is identical to RC4, but with a range coder that isn't buggy

Burrows-Wheeler Transform stage
   "A Block-sorting Lossless Data Compression Algorithm"  Mike Burrows and David J. Wheeler

MTF-2 stage
   "One attempt of a compression algorithm using the BWT."  Bernhard Balkenhol and Yuri M. Shtarkov

Structured model stage
   "Block Sorting Text Compression -- Final Report"  Peter Fenwick
   bzip1 source code   Julian Seward

Range coder
   7-zip source code, 2009 Igor Pavlov

**************************************************************************/

#ifndef __TDP2_RC5_HPP__
#define __TDP2_RC5_HPP__

#include "tdp2.hpp"

namespace TDP
{
	namespace Compression
	{
		namespace RC5
		{
			UInt32 CompressBlock(const void *input, void *tempspace, UInt32 count, void *ftab);
			bool DecompressBlock(const void *input, void *tempspace, UInt32 compressedSize, UInt32 decompressedSize);

			template<UInt32 _TmaxBlockSize>
			class Compressor
			{
				UInt32 _ftab[65537];
				UInt8 _inputStorage[_TmaxBlockSize];
				UInt32 _forceAlign;
				UInt8 _data[_TmaxBlockSize*8 + 160];
				UInt32 _outputSize;

			public:
				inline void *Storage()
				{
					return _inputStorage;
				}

				inline const void *Data() const
				{
					return _data;
				}

				inline UInt32 DataSize() const
				{
					return _outputSize;
				}

				void Compress(UInt32 size)
				{
					_outputSize = CompressBlock(_inputStorage, _data, size, _ftab);
				}
			};

			
			template<UInt32 _TmaxBlockSize>
			class Decompressor
			{
				UInt8 _inputStorage[_TmaxBlockSize];
				UInt32 _forceAlign;
				UInt8 _data[_TmaxBlockSize*6 + 20];
				
			public:
				inline void *Storage()
				{
					return _inputStorage;
				}

				inline const void *Data() const
				{
					return _data;
				}

				inline UInt32 DataSize() const
				{
					return _outputSize;
				}

				bool Decompress(UInt32 compressedSize, UInt32 decompressedSize)
				{
					return DecompressBlock(_inputStorage, _data, compressedSize, decompressedSize);
				}
			};
		}
	}
}

#endif
